// Fill out your copyright notice in the Description page of Project Settings.
#include "simpleHttpObject.h"
#include "Engine/Engine.h"
#include "http.h"
#include "HttpManager.h"
#include "Interfaces/IHttpRequest.h"
#include "SimpleHttpFunctionLibrary.h"
#include <string>

TArray<UMK_SimpleHttpObj*> allRootSimpleHttpObj;


UMK_SimpleHttpObj::UMK_SimpleHttpObj()
	:m_lifeTyp(EMK_SimpleHttpLifeTyp::WaitInitialization)
{


}


void UMK_SimpleHttpObj::SelfAddTORoot() 
{
	if (!IsRooted()) {
		AddToRoot();
	}
	allRootSimpleHttpObj.AddUnique(this);
}

void UMK_SimpleHttpObj::RemoveAllFromRoot() 
{
	TArray<UMK_SimpleHttpObj*> tempAll = allRootSimpleHttpObj;
	for (UMK_SimpleHttpObj* obj : tempAll) 
	{
		obj->RemoveSelfFromRoot();
	}
	allRootSimpleHttpObj.Reset();
}

void UMK_SimpleHttpObj::RemoveSelfFromRoot()
{
	if (IsRooted()){
		RemoveFromRoot();
	}
	allRootSimpleHttpObj.Remove(this);
}

void UMK_SimpleHttpObj::ClearCallback() 
{
	backEvent.Clear();
}

bool UMK_SimpleHttpObj::SetCallBackEvent_Bp(F_SimpleHttpServerReturn e)
{
	return SetCallBackEvent(e);
}


bool UMK_SimpleHttpObj::SetCallBackEvent(const F_SimpleHttpServerReturn& e)
{
	if (m_lifeTyp == EMK_SimpleHttpLifeTyp::IsReplyOrIdle || m_lifeTyp == EMK_SimpleHttpLifeTyp::WaitInitialization)
	{
		//在空闲时才能修改
		backEvent.Clear();
		backEvent = e;
		m_lifeTyp = EMK_SimpleHttpLifeTyp::IsReplyOrIdle;
		return true;
	}
	else
	{
		GLog->Log(ELogVerbosity::Error, TEXT("Waiting for callback, please do not modify status"));
		return false;
	}
}


void UMK_SimpleHttpObj::HttpCallBack(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{

	m_lifeTyp = EMK_SimpleHttpLifeTyp::IsReplyOrIdle;

	FString MessageBody; //= TEXT("返回了》》》");
	FString black;
	// If HTTP fails client-side, this will still be called but with a NULL shared pointer!
	if (!Response.IsValid())
	{
		MessageBody += "{\"success\":\"Error: Unable to process HTTP Request!\"}";
	}
	else
	{
		black = MessageBody = Response->GetContentAsString();
		if (EHttpResponseCodes::IsOk(Response->GetResponseCode()))
		{
			downloadbuffer = TArray<uint8>(Response->GetContent());		
		}
	}

	//if (GEngine)GEngine->AddOnScreenDebugMessage(-1, 10, FColor::Red, TEXT("dack>>>") + MessageBody + TEXT("<<<len=") + FString::FromInt(MessageBody.Len()));
	//GLog->Log(TEXT("Response>>>") + MessageBody + TEXT("<<<len=") + FString::FromInt(MessageBody.Len()));
	OnCallBack(black);
	

}




//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

void UMK_SimpleHttpObj::OnCallBack(FString& back)
{
	FString messger = back;
	if (backEvent.IsBound())
	{
		const FSimpleHttpReplyData replyData 
			=FSimpleHttpReplyData(postDataBuffer.url, messger,this
				, postDataBuffer.userkeywords, postDataBuffer.userLinkObj);
		backEvent.Execute(replyData);
	}
	contentData.Empty();
}


void UMK_SimpleHttpObj::AddPostContentData(const TArray<uint8>& data)
{
	contentData = data;
}

bool UMK_SimpleHttpObj::StartPost_BP(const FMKSimpleHttpRequestData& data, FString& ess, bool forceStart)
{
	return StartPost(data, ess, forceStart);
}

/*开始一次请求
* @param	data				要请求的信息
* @param	ess				    错误反馈
* @param	forceStart			是否强制开始（无论上次请求是否返回）
* RETURN						是否开始成功
*/
bool UMK_SimpleHttpObj::StartPost(const FMKSimpleHttpRequestData& data, FString& ess, bool forceStart)
{
	if (data.url.Len()<=8)
	{
		ess = TEXT("ulr.IsEmpty()");
		return false;
	}

	postDataBuffer = data;
	if (m_lifeTyp != EMK_SimpleHttpLifeTyp::IsReplyOrIdle )
	{
		//上次没有返回
		if (forceStart)
		{
			contentData.Empty();
			//强行开始
			ess = TEXT("forceStart!!");
		}
		else
		{
			ess = TEXT("inPost!callBack->dmhttp");
			return false;
		}
	}
	m_lifeTyp = EMK_SimpleHttpLifeTyp::StartRequest;

	postDataBuffer.TryFinishUpHard();

	TSharedRef<IHttpRequest, ESPMode::ThreadSafe> FileUploadRequest = FHttpModule::Get().CreateRequest();
	downloadbuffer.Empty();
	SetHttpVerb(FileUploadRequest, postDataBuffer.typ);

	for (const auto& hards : postDataBuffer.hardMap)
	{
		if (hards.Key.Len() >= 1&& hards.Value.Len() >= 1) 
		{
			FileUploadRequest->SetHeader(hards.Key, hards.Value);
		}
	}

	FileUploadRequest->SetURL(postDataBuffer.url);
	if (postDataBuffer.data.Len() >= 4)
	{
		//FileUploadRequest->SetContentAsString(postDataBuffer.data);	
		//确保中文被正常编码
		TArray<uint8> strData;
		USimpleHttpFunctionLibrary::StringToUint8(postDataBuffer.data, strData);
		FileUploadRequest->SetContent(strData);
		//确保参数长度设置正确
		FileUploadRequest->SetHeader("Content-Length", FString::FromInt(strData.Num()));
	}

	if (data.typ == EMK_SimpleHttpPostTyp::POST&&contentData.Num() > 4)
	{
		FileUploadRequest->SetContent(contentData);	
		FileUploadRequest->SetHeader("Content-Length", FString::FromInt(contentData.Num()));
	}


	FileUploadRequest->OnProcessRequestComplete().BindUObject(this, &UMK_SimpleHttpObj::HttpCallBack);

	if (FileUploadRequest->ProcessRequest())
	{
		//if (GEngine)GEngine->AddOnScreenDebugMessage(-1, 16, FColor::Green, TEXT("Success  post>>") + postDataBuffer.data +TEXT("to")+ postDataBuffer.url);
		GLog->Log(TEXT("Success  post>>\r") + postDataBuffer.data + TEXT(" \r>>\r") + postDataBuffer.url);
		
		m_lifeTyp = EMK_SimpleHttpLifeTyp::WaitReply;
		ess = TEXT("post OK");
		return true;
	}
	else
	{
		m_lifeTyp = EMK_SimpleHttpLifeTyp::IsReplyOrIdle;
		if (GEngine)GEngine->AddOnScreenDebugMessage(-1, 64, FColor::Red, TEXT("post ") + postDataBuffer.data + TEXT("fail") + postDataBuffer.url);

		ess = TEXT("post Fild!!!");
		return false;
	}

	ess = "post start fild!!";
	return false;
}

bool UMK_SimpleHttpObj::StartPost(const FMKSimpleHttpRequestData& data
	, UVerificationOfsignatureBase* vstool
	, FString& ess, bool forceStart)
{
	FMKSimpleHttpRequestData dataPost = data;
	if (vstool)
	{
		dataPost = vstool->VerificationOfsignatureData(dataPost);
	}
	return StartPost(dataPost, ess, forceStart);
}


bool UMK_SimpleHttpObj::StartPostVS_BP(const FMKSimpleHttpRequestData& data
	, UVerificationOfsignatureBase* vstool
	, FString& ess, bool forceStart)
{
	return StartPost(data, vstool, ess, forceStart);
}


void UMK_SimpleHttpObj::SetHttpVerb(TSharedRef<class IHttpRequest, ESPMode::ThreadSafe>& request, EMK_SimpleHttpPostTyp typ)
{
	request->SetVerb(FMKSimpleHttpRequestData::GetHttpVerb(typ));
}
